package com.c0der.neat.example;

import com.c0der.neat.Config;
import com.c0der.neat.Genome;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Sin {
    private static double[] inputs;

    static {
        inputs = new double[1000];
        for (int i = 0; i < 1000; i++)
            inputs[i] = (float) i / 1000f - 0.5f;
    }

    public static final void run() throws Exception {
        Config config = new Config(
                1, 1,
                0.7f,
                0.7f,
                0.5f,
                0.5f,
                10000,
                -10000,
                0.7f,
                10000,
                -10000);
        List<Genome> populations = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Genome genome = new Genome(config);
            genome.mutate();
            populations.add(genome);
        }
        int generation = 0;
        while (true) {
            for (Genome genome : populations) {
                double fitness = 0;
                for (int i = 0; i < 1000; i++) {
                    double x = inputs[i];//Math.random() * 2 - 1;
                    double v = genome.evaluate(new double[]{x + 0.5f})[0];
                    fitness += Math.abs(Math.sin(x) - v);
                }
                genome.setFitness(fitness);
                if (fitness / 1000f < 0.000001f) {
                    System.out.println("generation@" + generation + " fitness:"
                            + genome.getFitness() + "/" + genome.getNodes().size() + "-" + genome.getConnections().size());
                    System.out.println(genome.toString());
                    return;
                }
            }
            populations.sort(new Comparator<Genome>() {
                @Override
                public int compare(Genome t0, Genome t1) {
                    Double v1 = Double.valueOf(t0.getFitness());
                    Double v2 = Double.valueOf(t1.getFitness());
                    int v = v1.compareTo(v2);
                    if (v == 0) {
                        v = Integer.compare(t0.getNodes().size(), t1.getNodes().size());
                        if (v == 0) {
                            v = Integer.compare(t0.getConnections().size(), t1.getConnections().size());
                        }
                    }
                    return v;
                }
            });

            Genome g1 = populations.get(0);
            Genome g2 = populations.get(1);
            Genome gl = populations.get(populations.size() - 1);
            System.out.println("generation@" + generation + " fitness:"
                    + g1.getFitness() + "/" + g1.getNodes().size() + "-" + g1.getConnections().size()
                    + "  " + g2.getFitness() + "/" + g2.getNodes().size() + "-" + g2.getConnections().size()
                    + "  " + gl.getFitness() + "/" + gl.getNodes().size() + "-" + gl.getConnections().size());
            populations.clear();
            for (int i = 0; i < 998; i++) {
                Genome genome = Genome.x(g1, g2);
                genome.mutate();
                populations.add(genome);
            }
            populations.add(g1);
            populations.add(g2);
            generation++;
        }
    }

    public static final void main(String[] args) throws Exception {
        run();
    }
}
